package com.ccc.boot.security.service.impl;

import com.ccc.boot.exception.BusinessException;
import com.ccc.boot.log.DBLog;
import com.ccc.boot.log.ILogService;
import com.ccc.boot.log.LogInfo;
import com.ccc.boot.response.ResponseCode;
import com.ccc.boot.response.ResponseResult;
import com.ccc.boot.security.cache.CaptchaCache;
import com.ccc.boot.security.cache.OnlineCache;
import com.ccc.boot.security.cache.TokenCache;
import com.ccc.boot.security.pojo.AuthUserData;
import com.ccc.boot.security.pojo.LoginParam;
import com.ccc.boot.security.service.AuthService;
import com.ccc.boot.security.service.OnlineService;
import com.ccc.boot.security.service.UserService;
import com.ccc.boot.security.util.AuthUtils;
import com.ccc.boot.util.LogUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * 认证——登录
 *
 * @author superC
 * @version 0.1.0
 * @date 2022/3/24
 */

@Service
@RefreshScope
public class AuthServiceImpl implements AuthService {

    protected static final Logger logger = LoggerFactory.getLogger(AuthServiceImpl.class);

    @Resource(name = "userService")
    private UserService userService;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    private AuthUtils authUtils;

    @Autowired
    private TokenCache tokenCache;

    @Autowired
    private CaptchaCache captchaCache;

    @Autowired
    private OnlineCache onlineCache;

    @Resource(name = "loginLogService")
    private ILogService loginLogService;

    @Resource(name = "onlineService")
    private OnlineService onlineService;

    @Override
    public ResponseResult wmsLogin(LoginParam loginParam, HttpServletRequest request) {
        ResponseResult responseResult = null;
        logger.info("登录账户：{}", loginParam.getUsername());

        /**
         * 验证码
         */
        if (StringUtils.isEmpty(loginParam.getVerCode())) {
            throw new BusinessException(ResponseCode.LOGIN_CAPTCHR_ISNULL);
        }
        if (StringUtils.isEmpty(loginParam.getRandom())) {
            throw new BusinessException(ResponseCode.PARAM_NOT_COMPLETE);
        }
        // 通过random从redis获取验证码
        String code = captchaCache.getVerCode2Redis(loginParam.getRandom());
        if (code == null) {
            throw new BusinessException(ResponseCode.LOGIN_CAPTCHA_EXPIPE);
        }
        if (!loginParam.getVerCode().equals(code)) {
            throw new BusinessException(ResponseCode.LOGIN_CAPTCHA_ERR);
        }

        /**
         * 通过用户名获取用户信息
         */
        UserDetails userDetails = userService.loadUserByUsername(loginParam.getUsername());

        if (userDetails == null) {
            throw new BusinessException(ResponseCode.LOGIN_ERROR_CODE);
        }

        // 密码错误
        if (!passwordEncoder.matches(loginParam.getPassword(), userDetails.getPassword())) {
            throw new BusinessException(ResponseCode.LOGIN_PASSWORD_ERROR);
        }

        try {
            AuthUserData authUserData = authUtils.getLoginUser(userDetails);
            // 生成token
            String token = authUtils.generateToken(authUserData);
            logger.info("生成token: {}", token);

            // 存储至Redis缓存中, value存储当前用户的认证信息
            tokenCache.cacheToken(token, authUserData);

            // 发送登录日志
            LogInfo logInfo = LogUtils.getLoginLog(request, authUserData.getUsername(), loginParam.getClientId(), token);
            DBLog.getInstance().setLogService(loginLogService).offerQueue(logInfo);

            // 发送在线用户统计   TODO 存储表中有个问题：当token自动失效的用户，无法进行及时清除；
            onlineService.insert(logInfo);

            responseResult = ResponseResult.success("登录成功", token);

        } catch (Exception e) {
            logger.error("【捕获异常】\r\n异常记录：", e);
            responseResult = ResponseResult.failure(ResponseCode.GENERATE_PREFIX_ERROR);
        }
        return responseResult;
    }

    @Override
    public ResponseResult appLogin(LoginParam loginParam, HttpServletRequest request) {
        return null;
    }

    /**
     * 登出
     *
     * @param request
     * @date 2022/5/1 20:16
     * @author superC
     */

    @Override
    public void logout(HttpServletRequest request) {
        String token = authUtils.getToken(request);
        // 删除 token 从而实现注销
        tokenCache.deleteToken(token);

        // 删除在线登录用户数据
        onlineService.delete(token);

    }

}
